package com.maiko.usercenter.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maiko.usercenter.annotation.AuthCheck;
import com.maiko.usercenter.annotation.RateLimiter;
import com.maiko.usercenter.common.BaseResponse;
import com.maiko.usercenter.common.ErrorCode;
import com.maiko.usercenter.common.ResultUtils;
import com.maiko.usercenter.constant.RateLimiterKeyConstants;
import com.maiko.usercenter.exception.BusinessException;
import com.maiko.usercenter.model.dto.*;
import com.maiko.usercenter.model.entity.User;
import com.maiko.usercenter.model.vo.LoginUserVO;
import com.maiko.usercenter.service.UserService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import org.springframework.beans.BeanUtils;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;

import java.util.concurrent.TimeUnit;

/**
 * 用户接口
 * @author: Maiko7
 * @create: 2025-07-13 11:24
 */
@RestController
@RequestMapping("/user")
@Tag(name = "用户模块")
public class UserController {

    @Resource
    private UserService userService;

    @Resource
    private PasswordEncoder passwordEncoder;


    // region 登录相关
    /**
     * 处理用户注册请求的端点
     * 使用@PostMapping注解指定HTTP POST方法
     * 使用@Operation注解提供OpenAPI文档中的操作信息
     * 使用@RateLimiter注解限制接口访问频率，防止恶意注册刷接口(如注册机攻击）
     *
     * @param userAccountRegisterRequest 包含用户注册信息的请求体，包括账号、密码和确认密码
     * @return 返回一个BaseResponse对象，包含注册成功后的新用户ID
     */
    @PostMapping("/register")
    @Operation(summary = "用户注册", description = "用户通过账号、密码、确认密码注册")
    @RateLimiter(key = RateLimiterKeyConstants.USER_REGISTER, permits = 3, time = 60, unit = TimeUnit.SECONDS)
    public BaseResponse<Long> userRegister(@RequestBody UserAccountRegisterRequest userAccountRegisterRequest) {
        /**
         * 那为什么我下面这个又要判空呢？
         * 因为你想啊你加的@NotBlank是加在字段上的，你这个用户账户注册请求体是没有加判空的
         */
        if (userAccountRegisterRequest == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "请求参数为空");
        }
//        String account = userAccountRegisterRequest.getAccount();
//        String password = userAccountRegisterRequest.getPassword();
//        String checkPassword = userAccountRegisterRequest.getCheckPassword();
        /**
         * 你字段上有 @NotBlank，加了 @Valid，Spring MVC 自动校验失败会抛出 MethodArgumentNotValidException
         * 所以不用写下面的判空了
         */
//        if (StrUtil.hasBlank(account, password, checkPassword)) {
//            return ResultUtils.error(ErrorCode.PARAMS_ERROR);
//        }
//        long result = userService.userRegister(account, password, checkPassword);
        long result = userService.userRegister(userAccountRegisterRequest);
        return ResultUtils.success(result);
    }


    /**
     * 处理用户登录请求
     *
     * 该方法使用@PostMapping注解来处理POST请求到/login路径的用户登录操作
     * 使用@Operation注解来描述接口的摘要信息，便于API文档生成
     * 通过@RateLimiter注解实现登录接口的速率限制，以防止恶意尝试，暴力破解密码
     *
     * @param userAccountLoginRequest 包含用户登录信息的请求体，包括账号和密码
     * @param request HTTP请求对象，用于获取请求相关的信息
     * @return 返回一个BaseResponse对象，其中包含登录成功的用户信息
     *
     * 方法首先检查传入的userAccountLoginRequest是否为空，如果为空则抛出业务异常
     * 随后调用userService的userLogin方法处理用户登录逻辑，并获取登录用户信息
     * 最后使用ResultUtils的成功方法封装登录用户信息并返回
     */
    @PostMapping("/login")
    @Operation(summary = "用户登录", description = "用户通过账号、密码登录")
    @RateLimiter(key = RateLimiterKeyConstants.USER_LOGIN, permits = 5, time = 60, unit = TimeUnit.SECONDS)
    public BaseResponse<LoginUserVO> userLogin(@RequestBody UserAccountLoginRequest userAccountLoginRequest, HttpServletRequest request ) {
        // 检查登录请求对象是否为空，为空则抛出异常
        if (userAccountLoginRequest == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "请求参数为空");
        }
        // 调用用户服务的登录方法，处理登录逻辑并获取登录用户信息
        LoginUserVO loginUserVO = userService.userLogin(userAccountLoginRequest, request);
        // 使用成功结果封装登录用户信息并返回
        return ResultUtils.success(loginUserVO);
    }

    /**
     * 处理用户退出登录的请求
     *
     * @param request HTTP请求对象，用于获取用户登录信息
     * @return 返回一个包含布尔值的BaseResponse对象，表示退出操作是否成功
     * @throws BusinessException 如果请求参数为空，则抛出业务异常
     */
    @PostMapping("/logout")
    @Operation(summary = "退出登录", description = "退出登录")
    public BaseResponse<Boolean> userLogout(HttpServletRequest request) {
        // 检查请求对象是否为空，如果为空则抛出异常
        if (request == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "请求参数为空");
        }
        // 调用用户服务的退出登录方法，并返回结果
        boolean result = userService.userLogout(request);
        return ResultUtils.success(result);
    }

    /**
     * 获取当前登录用户的信息
     *
     * @param request HTTP请求对象，用于获取用户登录信息
     * @return 返回一个包含用户信息的BaseResponse对象
     */
    @GetMapping("/curren")
    @Operation(summary = "获取当前登录用户信息", description = "获取当前登录用户信息")
    public BaseResponse<LoginUserVO> getCurrentUser(HttpServletRequest request) {
        // 调用用户服务获取当前登录用户信息，并返回结果
        LoginUserVO loginUserVO = userService.getLoginUser(request);
        return ResultUtils.success(loginUserVO);
    }

    // endregion
    // region 增删改查


    /**
     * 添加新用户接口
     *
     * 该方法主要用于管理员角色添加新用户信息到系统中
     * 它要求请求者必须具有管理员角色，并且请求受到每分钟最多5次的速率限制
     *
     * @param userAddRequest 包含用户添加请求的详细信息，不能为空
     * @param request HTTP请求对象，用于获取请求相关的信息
     * @return 返回一个包含新用户ID的BaseResponse对象
     * @throws BusinessException 如果请求参数为空或用户添加失败，抛出此异常
     */
    @PostMapping("/add")
    @Operation(summary = "添加用户", description = "添加用户")
    @AuthCheck(mustRole = "UserConstant.ADMIN_ROLE")
    @RateLimiter(key = RateLimiterKeyConstants.USER_ADD, permits = 5, time = 60, unit = TimeUnit.SECONDS)
    public BaseResponse<Long> addUser(@RequestBody UserAddRequest userAddRequest, HttpServletRequest request) {
        // 检查请求参数是否为空，如果为空则抛出异常
        if (userAddRequest == null) {
            throw new BusinessException(ErrorCode.NULL_ERROR, "请求参数为空");
        }

        // 创建一个新的User对象，并将请求参数中的属性复制到该对象中
        User user = new User();
        BeanUtils.copyProperties(userAddRequest, user);

        // 密码加密
        if (userAddRequest.getPassword() == null || userAddRequest.getPassword().isEmpty()) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码不能为空");
        }
        String encodedPassword = passwordEncoder.encode(userAddRequest.getPassword());
        user.setPassword(encodedPassword);

        // 调用UserService的save方法保存用户信息，如果保存失败则抛出异常
        boolean result = userService.save(user);
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "添加用户失败");
        }

        // 返回成功响应，包含新用户的ID
        return ResultUtils.success(user.getId());
    }

    /**
     * 处理用户删除请求的接口方法
     * 该方法使用POST请求映射到"/delete"路径，用于删除系统中的用户
     * 方法上添加了操作摘要和权限控制注解，同时应用了速率限制，以防止滥用
     *
     * @param userDeleteRequest 包含待删除用户ID的请求体，经过验证确保数据有效性
     * @param request HTTP请求对象，可用于获取请求相关信息
     * @return 返回一个BaseResponse对象，包含删除操作的成功与否状态
     *
     * 注意：该方法仅限管理员角色的用户调用，且每分钟最多调用两次
     */
    @PostMapping("/delete")
    @Operation(summary = "删除用户", description = "删除用户")
    @AuthCheck(mustRole = "UserConstant.ADMIN_ROLE")
    @RateLimiter(key = RateLimiterKeyConstants.USER_DELETE, permits = 2, time = 60, unit = TimeUnit.SECONDS)
    public BaseResponse<Boolean> deleteUser(@RequestBody @Valid UserDeleteRequest userDeleteRequest, HttpServletRequest request) {
        if (userDeleteRequest == null || userDeleteRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "id不能为空和负数");
        }
        return ResultUtils.success(userService.removeById(userDeleteRequest.getId()));
    }

    @PostMapping("/update")
    @Operation(summary = "更新用户信息", description = "更新用户信息")
    @AuthCheck(mustRole = "UserConstant.ADMIN_ROLE")
    @RateLimiter(key = RateLimiterKeyConstants.USER_UPDATE, permits = 5, time = 60, unit = TimeUnit.SECONDS)
    public BaseResponse<Boolean> updateUser(@RequestBody @Valid UserUpdateRequest userUpdateRequest, HttpServletRequest request) {
//        if (userUpdateRequest == null || userUpdateRequest.getId() == null || userUpdateRequest.getId() <= 0) {
//            throw new BusinessException(ErrorCode.PARAMS_ERROR, "id不能为空和负数");
//        }
        if (userUpdateRequest == null ) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "id不能为空和负数");
        }
        User user = new User();
        BeanUtils.copyProperties(userUpdateRequest, user);
        boolean result = userService.updateById(user);
        if (!result) {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "更新用户失败");
        }
        return ResultUtils.success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "管理员查询用户", description = "管理员查询用户")
    @AuthCheck(mustRole = "UserConstant.ADMIN_ROLE")
    public BaseResponse<User> getUserById(@RequestBody UserGetRequest userGetRequest, HttpServletRequest request) {
        if (userGetRequest == null || userGetRequest.getId() == null || userGetRequest.getId() <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "id不能为空和负数");
        }
        User user = userService.getById(userGetRequest.getId());
        if (user == null) {
            throw new BusinessException(ErrorCode.USER_NOT_EXIST, "用户不存在");
        }
        return ResultUtils.success(user);
    }

    @PostMapping("/search/page")
    @Operation(summary = "分页查询用户", description = "分页查询用户")
    @AuthCheck(mustRole = "UserConstant.ADMIN_ROLE")
    public BaseResponse<Page<User>> searchUserByPage(@RequestBody UserPageQueryRequest userPageQueryRequest, HttpServletRequest request) {
        if (userPageQueryRequest == null) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        long current = userPageQueryRequest.getCurrent();
        long pageSize = userPageQueryRequest.getPageSize();
        Page<User> userPage = userService.page(new Page<>(current, pageSize),
                userService.getQueryWrapper(userPageQueryRequest));
        return ResultUtils.success(userPage);

    }


    @PostMapping("/update/my")
    @Operation(summary = "用户更新自己个人信息", description = "用户更新自己个人信息")
    @RateLimiter(key = RateLimiterKeyConstants.USER_UPDATE_MY, permits = 5, time = 60, unit = TimeUnit.SECONDS)
    public BaseResponse<Boolean> updateMyUser(@RequestBody  UserUpdateMyRequest userUpdateMyRequest, HttpServletRequest request) {
        if (userUpdateMyRequest == null) {
            return new BaseResponse<>(ErrorCode.NULL_ERROR, "参数为空");
        }
        LoginUserVO loginUser = userService.getLoginUser(request);
        User user = new User();
        // 从 userUpdateMyRequest 对象中复制所有属性值到 user 对象中，
        BeanUtils.copyProperties(userUpdateMyRequest, user);
        user.setId(loginUser.getId());
        // 判断是否有密码需要更新
        if (userUpdateMyRequest.getPassword() != null && !userUpdateMyRequest.getPassword().isEmpty()) {
            // 对密码加密（用 BCrypt）
            String encodedPassword = passwordEncoder.encode(userUpdateMyRequest.getPassword());
            user.setPassword(encodedPassword);
        }
        boolean result = userService.updateById(user);
        if (!result) {
            return new BaseResponse<>(ErrorCode.OPERATION_ERROR, "更新失败");
        }
        return ResultUtils.success(true);

    }


















/**
 * 你要学会它这个测试的思路，搞一个@GetMapping("/test")测试
 */
//    @GetMapping("/test")
//    public BaseResponse<String> test(@RequestParam  String name) {
//        return ResultUtils.success("hello " + name);
//    }





}
